Java webSocket 网页聊天室

webSocket简介

webSocket是ajax轮询与long pull方式的改进。ajax轮询:每隔一段时间请求一次,不管有没有新信息;long pull:每次请求之后,等到有新信息才会返回;webSocket:客户端发送一次请求之后,只要有新信息,服务器就会主动把数据推送过去。

效果截图

参考了网上的例子来实现聊天室,实验楼的那个不错!但是,打开两个页面却不能真正的聊天,后面参考Tomcat下的ChatAnnotation.java综合两者,才有了这个聊天室。

效果图1:
交互聊天

效果图2:
用户下线系统消息

增加代码

后台代码增加以下几点:

  • 1、在会话打开时,将对应的session添加到对应map中;
  • 2、当发送消息时,遍历整个map,然后对每个session发送消息;
  • 3、关闭时,将对应的session从map中删除,不再接收消息,并且如果此用户有发送过消息,系统将提示该用户已下线
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
* 聊天服务器类
*
* @author yuechang
*
*/
@ServerEndpoint("/websocket")
public class ChatServer {

private Session session;
private static final Map<ChatServer, String>
connections = new ConcurrentHashMap<ChatServer, String>();

// 日期格式化
private static final SimpleDateFormat
DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm");

/**
* @category 添加初始化操作
* @param session
*/
@OnOpen
public void open(Session session) {

// 开启会话,将session存入map中,不过此时的nikename存入的为空字符串
this.session = session;
connections.put(this, "");
}

/**
* @category 接受客户端的消息,并把消息发送给所有连接的会话
* @param message
* 客户端发来的消息
* @param session
* 客户端的会话
*/
@OnMessage
public void getMessage(String message, Session session) {

// 把客户端的消息解析为JSON对象
JSONObject jsonObject = JSONObject.fromObject(message);
// 获得昵称
String nikename = (String) jsonObject.get("nickname");

connections.put(this, nikename);
broadcast(message);
}

/**
* @category 添加关闭会话时的操作
* @param reason
*/
@OnClose
public void close(CloseReason reason) {

String nikename = connections.get(this);
// 下线时,得从总人数中移除,否则信息公布时找不到下线的session报错的
connections.remove(this);
// 如果这个人有在聊天室中发过言,则向聊天室中发送nikename已下线消息
if (StringUtils.isNotBlank(nikename)) {
String msg = "{'content':'<p>用户[ ".concat(nikename)
.concat(" ]下线了!<br/></p>','nickname':'系统消息'}");
broadcast(msg);// 这是告知所还在线聊天的人下线了
}
}

/**
* @category 添加处理错误的操作
* @param t
*/
@OnError
public void error(Throwable t) {
// 添加处理错误的操作
}

/**
* @category 广播消息
* @param msg
* 消息JSON串
*/
private void broadcast(String msg) {

Iterator<ChatServer> iterator = connections.keySet().iterator();
while (iterator.hasNext()) {
ChatServer client = iterator.next();
synchronized (client) {

// 把客户端的消息解析为JSON对象
JSONObject jsonObject = JSONObject.fromObject(msg);
// 在消息中添加发送日期
jsonObject.put("date", DATE_FORMAT.format(new Date()));

// 添加本条消息是否为当前会话本身发的标志
jsonObject.put("isSelf", client.session.equals(session));
// 发送JSON格式的消息
client.session.getAsyncRemote().sendText(jsonObject.toString());
}
}
}
}

遇到的问题

在Maven项目中,由于web.xml申明的web-app是2.3版本的,不支持JSP内置对象,需要进行web.xml申明为:

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
</web-app>

然后再JSP页面加上:

1
<%@ page isELIgnored="false" %>

项目下载地址

https://github.com/yuechang/webSocket.git

博文参考: